package com.tangpei.display
{
	import com.tangpei.events.FrameEvent;
	import com.tangpei.interfaces.IAnimatedDisplayObject;
	import com.tangpei.interfaces.IFuckedUp;
	import com.tangpei.utils.FrameRateTimer;
	
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.JointStyle;
	import flash.events.TimerEvent;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	
	/**
	 * An AnimatedBitmap is a bitmap object that uses a sequence of images
	 * from a provided bitmap to play an animation. 
	 * @author TangPei
	 * 
	 */	
	public class AnimatedBitmap extends Bitmap implements IAnimatedDisplayObject,IFuckedUp
	{
		
		private var _buffer:BitmapData;
		
		private var _timer:FrameRateTimer;
		
		private var _isPlaying:Boolean;
		
		private var _currentFrame:int;
		
		private var _totalFrames:int;
		
		private var _point:Point;
		
		private var _rect:Rectangle;
		
		public function AnimatedBitmap(bitmapData:BitmapData,width:int,height:int,timer:FrameRateTimer,transparent:Boolean=true, pixelSnapping:String="auto", smoothing:Boolean=false)
		{
			super(new BitmapData(width,height,transparent,0x00000000), pixelSnapping, smoothing);
			_buffer=bitmapData.clone();
			_totalFrames=_buffer.width/width;
			_currentFrame=1;
			_isPlaying=false;
			_timer=timer;
			_point=new Point(0,0);
			_rect=new Rectangle(0,0,width,height);
			bitmapData.copyPixels(_buffer,_rect,_point);
			
		}
		
		public function get currentFrame():int
		{
			return this._currentFrame;
		}
		
		public function get frameRate():int
		{
			return _timer.frameRate;
		}
		
		
		/**
		 * Jumps to the specified frame and plays the animated
		 * bitmap from that position. Note that the frames of an
		 * animated bitmap start at 1.
		 * 
		 * @param frame the frame number which to jump.
		 * 
		 */		
		public function gotoAndPlay(frame:int):void
		{
			this._currentFrame=frame-1;
			play();
		}
		
		/**
		 * Jumps to the specified frame and stops the animated
		 * bitmap at that position. Note that the frames of an
		 * animated bitmap start at 1.
		 *
		 * @param frame The frame number which to jump.
		 */
		public function gotoAndStop(frame:int):void
		{
			if(_currentFrame>=frame)
			{
				_currentFrame-=1;
				nextFrame();
			}
			else
			{
				_currentFrame+=1;
				preFrame();
			}
		}
		
		/**
		 * Returns whether the animated bitmap is playing or not.
		 *
		 * @return true if the animated bitmap is playing, else false.
		 */
		public function isPlaying():Boolean
		{
			return false;
		}
		
		/**
		 * Moves the animation to the next of the current frame.
		 * If the animated bitmap is playing, the playback is
		 * stopped by this operation.
		 */
		public function nextFrame():void
		{
			if(_isPlaying)
			{
				stop();
			}
			_currentFrame++;
			if(_currentFrame>_totalFrames)
			{
				_currentFrame=_totalFrames;
			}
			draw();
		}
		
		
		/**
		 * Starts the playback of the animated bitmap. If the animated
		 * bitmap is already playing while calling this method, it calls
		 * stop() and then play again instantly to allow for framerate
		 * changes during playback.
		 */
		public function play():void
		{
			if(!_isPlaying)
			{
				_isPlaying=true;
				_timer.addEventListener(TimerEvent.TIMER,onTimerHandler);
				_timer.start();
			}
			else
			{
				stop();
				play();
			}
		}
		/**
		 * plays the animation forward by one frame. 
		 * @param event
		 * 
		 */		
		private function onTimerHandler(event:TimerEvent):void
		{
			_currentFrame++;
			if(_currentFrame>_totalFrames)
			{
				_currentFrame=1;
			}
			else if(_currentFrame<1)
			{
				_currentFrame=_totalFrames;
			}
			draw();
		}
		
		/**
		 * draw the next bitmap from the buffer to the animated bitmap. 
		 * 
		 */		
		private function draw():void
		{
			dispatchEvent(new FrameEvent(FrameEvent.ENTER));
			_rect=new Rectangle((_currentFrame-1)*width,0,width,height);
			bitmapData.copyPixels(_buffer,_rect,_point);
		}
		/**
		 *  Moves the animation to the previous of the current frame.
		 * If the animated bitmap is playing, the playback is
		 * stopped by this operation.
		 * 
		 */		
		public function preFrame():void
		{
			if(_isPlaying)
			{
				stop();
			}
			_currentFrame--;
			if(_currentFrame<1)
			{
				_currentFrame=1;
			}
			draw();
		}
		
		/**
		 * Returns the frame rate with that the animated bitmap is playing.
		 *
		 * @return The fps value of the animated bitmap.
		 */
		public function setFrameRateTimer(timer:FrameRateTimer):void
		{
			if(_isPlaying)
			{
				stop();
				_timer=timer;
				play();
			}
			else
			{
				_timer=timer;
			}
		}
		
		
		/**
		 * Stops the playback of the animated bitmap.
		 */
		public function stop():void
		{
			if(_isPlaying)
			{
				_timer.stop();
				_timer.removeEventListener(TimerEvent.TIMER,onTimerHandler);
				_isPlaying=false;
			}
		}
		
		/**
		 * Returns the total amount of frames that the animated bitmap has.
		 *
		 * @return The total frame amount.
		 */
		public function get totalFrames():int
		{
			return this._totalFrames;
		}
		
		public function fuckedUp():void
		{
			stop();
			this.bitmapData.dispose();
			this._buffer.dispose();
			_rect=null;
			_point=null;
		}
		
	}
}